package redis.client.nedis.request;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import redis.client.nedis.HostAndPort;
import redis.client.nedis.reply.IReply;
import redis.client.nedis.util.UnsafeIdUtil;

import java.util.HashMap;
import java.util.Map;

/**
 * 全局redis请求池
 *
 * @author Administrator
 */
public class RequestPool {
    private static Map<HostId, RedisRequest> requestPool = new HashMap<>();
    private static Map<HostAndPort, Long> idMap = new HashMap<>();

    /**
     * redis请求时放入
     *
     * @param request
     */
    public static synchronized void putRequest(RedisRequest request) {
        requestPool.put(HostId.build(request.getHostAndPort(), request.getId()), request);
    }

    /**
     * 移除request
     *
     * @param request
     */
    public static synchronized void removeRequest(RedisRequest request) {
        RedisRequest rq = requestPool.remove(HostId.build(request.getHostAndPort(), request.getId()));
        rq = null;
    }

    /**
     * 放入redis结果
     *
     * @param reply
     */
    public static synchronized void putResult(HostAndPort hp, IReply<?> reply) {

        Long id = idMap.get(hp);
        if (id == null) {
            id = UnsafeIdUtil.Init;
        }

        HostId hi = HostId.build(hp, id);
        RedisRequest rq = requestPool.get(hi);
        rq.setReply(reply);
        rq.getSemaphore().release();

        idMap.put(hp, UnsafeIdUtil.getNextId(id));
    }

    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    static class HostId {
        private HostAndPort hostAndPort;
        private long id;

        @Override
        public int hashCode() {
            return hostAndPort.hashCode() + (int) id;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (obj == this) {
                return true;
            }
            if (!(obj instanceof HostId)) {
                return false;
            }

            HostId hi = (HostId) obj;
            return this.id == hi.id && this.hostAndPort.equals(hi.getHostAndPort());
        }

        public static HostId build(HostAndPort hp, long id) {
            return new HostId(hp, id);
        }
    }
}
